<template>
  <div class="kline-chart">
    <div class="tabsWrap">
      <div :class="{active:active==='period'}" @click="active= active==='period'?'':'period'"><span>{{currentInterval.label}}</span></div>
      <div :class="{active:active==='ma'}" @click="active= active==='ma'?'':'ma'"><span>{{ma?ma:$t('kline.均线')}}</span></div>
      <div :class="{active:active==='indicator'}" @click="active= active==='indicator'?'':'indicator'"><span>{{indicator?indicator:$t('kline.指标')}}</span></div>
      <div v-show="interval!='1s'" :class="{active:active==='type'}" @click="active= active==='type'?'':'type'"><span>{{currentType.label}}</span></div>
      <ul class="dropMenu clearfix" v-show="active==='period'">
        <li :class="{active:interval===item.resolution}" @click="setInterval(item)" v-for="item in Intervals" :key="item.resolution">{{item.label}}</li>
      </ul>
      <ul class="dropMenu clearfix" v-show="active==='ma'">
        <li :class="{active:ma==item}" @click="setMA(item)" v-for="item in Averages" :key="item">{{item}}</li>
        <li :class="{active:!ma}" @click="setMA('')">{{$t('kline.关闭')}}</li>
      </ul>
      <ul class="dropMenu clearfix" v-show="active==='indicator'">
        <li :class="{active:indicator===item}" @click="setIndicator(item)" v-for="item in Indicators" :key="item">{{item}}</li>
        <li :class="{active:indicator===''}" @click="setIndicator('')">{{$t('kline.关闭')}}</li>
      </ul>
      <ul class="dropMenu clearfix" v-show="active==='type'">
        <li :class="{active:chartType===item.key}" @click="setChartType(item)" v-for="item in ChartTypes" :key="item.key">{{item.label}}</li>
      </ul>
    </div>
    <div class="price tc"><p class="ellipsis">{{$t('kline.开')}} = <span :style="{color:color}">{{getPrice('open')}}</span> {{$t('kline.高')}} = <span :style="{color:color}">{{getPrice('high')}}</span> {{$t('kline.低')}} = <span :style="{color:color}">{{getPrice('low')}}</span> {{$t('kline.收')}} = <span :style="{color:color}">{{getPrice('close')}}</span></p></div>
    <div :id="domId" class="chartView"></div>
    <transition transitionenter-active-class="animated short fadeIn" leave-active-class="animated short fadeOut">
      <f-loading v-show="loading" :size="40"/>
    </transition>
  </div>
</template>

<script>
import {dispose, init} from 'klinecharts/index.blank'
import Config from './config'
// import generatedKLineDataList from '@/assets/js/generatedKLineDataList'
import { toFixed } from '@/utils'
import { computed, onMounted, onUnmounted, reactive, toRefs, watch, watchEffect } from 'vue'
import { useI18n } from 'vue-i18n'

const setChartSetting = (key, val)=>{
  let _chartSetting = JSON.parse(localStorage.getItem('chartSetting') || '{}')
  _chartSetting[key] = val
  localStorage.setItem('chartSetting', JSON.stringify(_chartSetting))
}

const getChartSetting = (key, defaultVal)=>{
  let _chartSetting = JSON.parse(localStorage.getItem('chartSetting') || '{}')
  return _chartSetting[key] || defaultVal
}

const setKlineData = (market, interval, val)=>{
  let _klineData = JSON.parse(localStorage.getItem('klineData') || '{}')
  !_klineData[market] && (_klineData[market]={})
  _klineData[market][interval] = val
  localStorage.setItem('klineData', JSON.stringify(_klineData))
}

const getKlineData = (market, interval, defaultVal)=>{
  let _klineData = JSON.parse(localStorage.getItem('klineData') || '{}')
  return _klineData[market] &&  _klineData[market][interval] || defaultVal
}

export default {
  name: 'KlineChart',
  props: {
    //Dom元素id
    domId: {
      type: String,
      default: function () {
        return "klineChart";
      },
    },
    //参数
    market: {
      type: String,
      default: function () {
        return "";
      },
    },
    // 价格精度
    pricePrecision: {
      type: Number,
      default: function () {
        return 4;
      },
    },
    // 数量精度
    volumePrecision: {
      type: Number,
      default: function () {
        return 4;
      },
    },
    //设置单次加载的k线数量
    length: {
      type: Number,
      default: function () {
        return 200;
      },
    },

  },
  setup(props, ctx){
    const {t} = useI18n()
    const kline = reactive({
      loading:false,
      kLineModel:{},
      color: '',
      active:'',
      interval: getChartSetting('interval', '30'),
      ma:getChartSetting('ma', ''),
      indicator:getChartSetting('indicator', 'VOL'),
      chartType:getChartSetting('chartType', 'candle_solid'),
    })

    const Intervals = Config.Intervals.map(item=>{
      let _resolution = item.resolution
      if(!isNaN(_resolution)){
        _resolution = _resolution/60 < 1 ? _resolution+'m' : _resolution/60+'h'
      }
      item.label = _resolution == '1s' ? t('kline.s') : _resolution.substr(0, _resolution.length-1) + t(`kline.${_resolution.substr(_resolution.length-1)}`)
      return item
    })

    const currentInterval = computed(() => Intervals.find(item => {
      return item.resolution == kline.interval
    }))
    const currentType = computed(() => Config.ChartTypes.find(item => item.key == kline.chartType))

    let kLineChart = null, paneTag = null

    onMounted(() => {
      //实现自定义的k线提示显示规则
      Config.Style.candle.tooltip.labels = []
      Config.Style.candle.tooltip.values = kLineData => {
        const change = kLineData.close - kLineData.open
        kline.kLineModel = kLineData
        kline.color = change==0?Config.Style.candle.bar.noChangeColor:(change < 0 ? Config.Style.candle.bar.downColor : Config.Style.candle.bar.upColor)
      }
      kLineChart = init(props.domId, Config.Style)
      kLineChart.setOffsetRightSpace(30)
      kLineChart.setPriceVolumePrecision(props.pricePrecision, props.volumePrecision)
      setInterval(currentInterval.value, true)
      kline.ma && setMA(kline.ma)
      paneTag = kLineChart.createPane('technicalIndicator', kline.indicator? { technicalIndicatorType: kline.indicator}:undefined)
      kLineChart.applyNewData(getKlineData(props.market, kline.interval, []), false)
      kLineChart.loadMore(firstKlineTimestamp=>{
        queryKlineData(false, Math.floor(firstKlineTimestamp/1000))
      })
      queryKlineData()

      watch(()=>kline.interval, (_new)=>update(_new))
      watch(()=>props.market, (_new, _old)=>{
        if(!_old){
          update()
        }
      })

      watchEffect(()=>{
        kLineChart.setPriceVolumePrecision(props.pricePrecision, props.volumePrecision)
      })
    })

    onUnmounted(() => {
      dispose(props.domId)
      window.gws && window.gws.unsubscribe("kline")
    })

    const update = (interval)=>{
      interval = interval || kline.interval
      kLineChart.applyNewData(getKlineData(props.market, interval, []), false)
      queryKlineData()
    }

    /* 
    @init 是否加载初始k线数据
    @more 是否还有更多历史数据
     */
    const queryKlineData = (init=true, timestamp)=>{
      if(!props.market){
        return 
      }
      if(init){
        kline.loading = true
      }
      window.gws.subscribe({
        //查询最新k线数据
        target: "kline",
        method: "query",
        symbol: props.market.toLowerCase(),
        period: kline.interval,
        timestamp,
        length: props.length,
        callback: (res) => {
          kline.loading = false
          const _data = dataFactory(res || [])
          const _more = _data.length >= props.length
          if(init){
            kLineChart.applyNewData(_data, _more)
            setKlineData(props.market, kline.interval, _data)
            subKlineData()
          } else {
            kLineChart.applyMoreData(_data, _more)
            setKlineData(props.market, kline.interval, kLineChart.getDataList())
          }
        },
      });
    }

    const subKlineData = ()=>{
      window.gws.subscribe({
        //订阅最新k线数据
        target: "kline",
        method: "sub",
        symbol: props.market.toLowerCase(),
        period: kline.interval,
        callback: (res) => {
          const _data = dataFactory(res && res[2] || [])
          for(let item of _data){
            kLineChart.updateData(item)
          }
          setKlineData(props.market, kline.interval, kLineChart.getDataList())
        },
      });
    }

    const dataFactory = datas=>{
      // K线图数据整理
      datas = datas.map(item=>{
        const kLineModel = {
          timestamp: item[0] * 1000,
          open: Number(item[1]),
          high: Number(item[2]),
          low: Number(item[3]),
          close: Number(item[4]),
          volume: Number(item[5])
        }
        kLineModel.turnover = Number(toFixed((kLineModel.open + kLineModel.close + kLineModel.high + kLineModel.low) / 4 * kLineModel.volume, props.volumePrecision))
        return kLineModel
      })
      return datas
    }

    const getPrice = key=>{
      return kline.kLineModel[key] && toFixed(kline.kLineModel[key], props.pricePrecision) || 'n/a'
    }

    const setInterval = (item , init = false)=>{
      kline.active=''
      const func = ()=>{
        kline.interval = item.resolution
        setChartSetting('interval', item.resolution)
        kLineChart.setStyleOptions({
          candle: {
            type: item.chartType || kline.chartType
          }
        })
      }
      if(init){
        func()
      }
      window.gws && window.gws.unsubscribe("kline").then(func)
    }

    const setIndicator = item=>{
      kline.indicator = item
      kline.active=''
      setChartSetting('indicator', item)
      if(item){
        if(paneTag){
          kLineChart.setTechnicalIndicatorType(item, false, paneTag)
        } else {
          paneTag = kLineChart.createPane('technicalIndicator', { technicalIndicatorType: item})
        }
      } else {
        kLineChart.removeTechnicalIndicator(kline.indicator, paneTag)
        paneTag = null
      }
    }

    const setMA = item=>{
      kline.ma = item
      kline.active=''
      setChartSetting('ma', item)
      if(item){
        kLineChart.setTechnicalIndicatorType(item)
      } else {
        kLineChart.removeTechnicalIndicator(kline.ma)
      }
    }

    const setChartType = item=>{
      if(kline.interval!='1s'){
        kline.chartType = item.key
        kline.active=''
        setChartSetting('chartType', item.key)
        kLineChart.setStyleOptions({
        candle: {
            type: item.key
          }
        })
      }
    }


    return {
      ...toRefs(kline),
      Intervals,
      Averages: Config.Averages,
      Indicators: Config.Indicators,
      ChartTypes: Config.ChartTypes,
      currentInterval,
      currentType,
      getPrice,
      setInterval,
      setIndicator,
      setMA,
      setChartType
    }
  }
}
</script>

<style lang="less" scoped>
.kline-chart {
  position: relative;
  height: 100%;
  width: 100%;
  display: flex;
  flex-direction: column;
  .tabsWrap {
    text-align: center; padding-left: 15PX; padding-right: 15PX; line-height: 30PX; display: flex; font-size: 12PX;  position: relative; z-index: 4; background-color: #1F2837;
    > div {min-width: 80px; position: relative; flex: 1;}
    > div:after {content: ''; position: absolute; right: 4PX;bottom: 0; border-left: 6PX solid #999; border-top: 6PX solid transparent; border-bottom: 6PX solid transparent; transform: rotate(45deg);}
    > div.active {background-color: #122544; color: #9596aa;}
    .dropMenu {position: absolute; background-color: #122544; left: 0; right: 0; top: 30PX; z-index: 1; color: #9596aa; font-size: 14PX; text-align: center}
    .dropMenu li {width: 20%; float: left; line-height: 35PX;}
    .dropMenu li.active {background-color: #0067e7; color: #fff;}
  }
  .price {
    text-align: center; font-size: 12PX; margin-top: 6PX; position: relative; height: 15PX; overflow: hidden;
    p {position: absolute;  -webkit-transform: scale(0.825); transform: scale(0.825); left: 0; right: 0;}
    .price p span + span {margin-left: 5PX;}
  }
  .chartView {
    flex: 1;
  }
  
}
</style>

